#include "asan_interceptors.h"
#include "asan_internal_defs.h"
#include "asan_report.h"
#include "asan_alloctor.h"
#include "asan_shadow_memory.h"
#include "asan_utils.h"
#include "common_flags.h"
#include "asan_signal_handler.h"


namespace __sanitizer {

uptr __asan_shadow_memory_dynamic_address;        // Global interface symbol.
int __asan_option_detect_stack_use_after_return;  // Global interface symbol.
uptr *__asan_test_only_reported_buggy_pointer;    // Used only for testing asan.

uptr kHighMemEnd, kMidMemBeg, kMidMemEnd;

bool asan_inited = false;
bool asan_init_is_running = false;
bool asan_interceptor_inited = false;

int InitializeAlloctor() {
  AsanShadowMem *shadow = (AsanShadowMem*)REAL(malloc(sizeof(AsanShadowMem)));
  shadow->InitShadow();
  allocatorPtr = (Allocator*)REAL(malloc(sizeof(Allocator)));
  allocatorPtr->OnInit(shadow);
}

void InitializePageSize() {
  ASAN_TOTAL_PHYS_PAGES = sysconf(_SC_PHYS_PAGES);
  ASAN_PAGE_SIZE = sysconf(_SC_PAGE_SIZE);
  // ASAN_TOTAL_PHYS_PAGES = 0x100000;
  // ASAN_PAGE_SIZE = 4096;
}

void InitializeHighMemEnd() {
  kHighMemEnd = (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
  kHighMemEnd |= (ASAN_PAGE_SIZE << ASAN_SHADOW_SCALE) - 1;
}

void InitializeFlags() {
  SetCommonFlagsDefaults();
  InitializeAsanFlags();
}

}  // namespace __sanitizer

extern "C" {

using namespace __sanitizer;

void NOINLINE __asan_handle_no_return() {
  if (asan_init_is_running)
    return;
  // read the proc/pid/maps to get the mapped stack segment
  // the clear the whole stack
  // TODO: we need a AsanThread for each thread
}

void __asan_init() {
  if (asan_inited) return;
  asan_inited = false;
  asan_init_is_running = true;
  asan_interceptor_inited = false;
  InitializeFlags();
  InitializePageSize();
  InitializeHighMemEnd();
  InitializeAsanInterceptors();
  asan_interceptor_inited = true;
  // Cannot print anything before this line!!!
  VReport(ASAN_LOG_DEBUG, "InitializeAsanInterceptors\n");
  VReport(ASAN_LOG_DEBUG, "kHighMemEnd = %llx\n", kHighMemEnd);
  VReport(ASAN_LOG_DEBUG, "ASAN_PAGE_SIZE = %d\n", ASAN_PAGE_SIZE);
  InitializeAlloctor();
  InstallDeadlySignalHandler(DeadlySignalHandler);
  VReport(ASAN_LOG_DEBUG, "Finish __asan_init\n");
  asan_inited = true;
  asan_init_is_running = false;
}

}
